#coding: utf8
class BaseCalculator(object):
    def __init__(self):
        self.default_insert_score = -40
        self.default_delete_score = -35
        self.default_replace_score = -20
        self.default_match_score = 50

    @property
    def defalut_scores(self):
        return (self.default_insert_score, self.default_delete_score, 
                self.default_replace_score, self.default_match_score)

    def get_match_score(self, src, dst):
        raise NotImplementedError 

    def get_replace_score(self, src, dst):
        raise NotImplementedError 

    def get_insert_score(self, dst):
        raise NotImplementedError 

    def get_delete_score(self, src):
        raise NotImplementedError 

    def is_the_same(self, src, dst):
        raise NotImplementedError 

class GrammarCalculator(BaseCalculator):
    def __init__(self):
        #BaseCalculator.__init__(self)
        super(GrammarCalculator, self).__init__()
        self.espec_weight = {'PU': (-5, -1, -10, self.default_match_score/3), 
                'NP': (-30, -30, -25, 50), 
                'VP': (-30, -30, -25, 50), 
                'SP': (-15, -15, -20, 15),
                #'DP': (-15, -15, -20, 50),
                '~': (-50, -40, -25, 60),
                'ADVP': (-15, -15, -15, 50),
                'M': (-5, -1, -10, self.default_match_score/3),
                'DEC': (-5, -1, -10, self.default_match_score/3),
                'CD': (-35, -10, -20, self.default_match_score/2),
                }
        self.equal_replace = [('NP', 'DP', 0.8)]
        #print self.default_delete_score

    def get_match_score(self, src, dst):
        if type(src) in (str, unicode): src = (None, src)
        if src[0] == dst:
            return self.default_match_score + 20
        elif src[1] == dst:
            return self.espec_weight.get(dst, self.defalut_scores)[3]
        else:
            raise ValueError('%s ---not match---%s' % (src, dst))

    def get_replace_score(self, src, dst):
        if type(src) in (str, unicode): src = (None, src)
        src = src[1]
        for equal_replace_pair in self.equal_replace:
            if (src, dst) == equal_replace_pair[:2] or (dst, src) == equal_replace_pair[:2]:
                return self.get_match_score(dst, dst) * equal_replace_pair[2]
        src_score = self.espec_weight.get(src, (0, 0, self.default_replace_score))[2]
        dst_score = self.espec_weight.get(dst, (0, 0, self.default_replace_score))[2]
        return src_score + dst_score + self.get_match_score(dst, dst) / 3 

    def get_insert_score(self, dst):
        return self.espec_weight.get(dst, (self.default_insert_score, 0, 0))[0]

    def get_delete_score(self, src):
        if type(src) in (str, unicode): src = (None, src)
        return self.espec_weight.get(src[1], (0, self.default_delete_score, 0))[1]

    def is_the_same(self, src, dst):
        if type(src) in (str, unicode): src = (None, src)
        return True if src[0] == dst or src[1] == dst else False

grammar_calculator = GrammarCalculator()
del GrammarCalculator

class Judger:
    def __init__(self, calculator):
        self.calculator = calculator

    def get_max_score(self, array_to_match):
        return sum([ self.calculator.get_match_score(x, x) for x in array_to_match ])

    def get_score(self, array, array_to_match):
        src_len = len(array)
        dst_len = len(array_to_match)
        dp = [ [-100000000] * (dst_len + 1) for x in range(src_len + 1) ]
        dp[0][0] = 0

        for x in range(src_len + 1):
            for y in range(dst_len + 1):
                src_one = array[x - 1]
                dst_one = array_to_match[y - 1]
                if x > 0 and y > 0:
                    if self.calculator.is_the_same(src_one, dst_one):
                        dp[x][y] = max(dp[x][y], dp[x-1][y-1] + self.calculator.get_match_score(src_one, dst_one))
                    else:
                        dp[x][y] = max(dp[x][y], dp[x-1][y-1] + self.calculator.get_replace_score(src_one, dst_one))

                if x > 0:
                    dp[x][y] = max(dp[x][y], dp[x-1][y] + self.calculator.get_delete_score(src_one))
                if y > 0:
                    dp[x][y] = max(dp[x][y], dp[x][y-1] + self.calculator.get_insert_score(dst_one))
                #print 'dp[%d][%d]' % (x, y), dp[x][y]

        #print '%d, %d'%(dp[src_len][dst_len], self.get_max_score(array_to_match))
        return dp[src_len][dst_len] * 100.0 / self.get_max_score(array_to_match)

if __name__ == '__main__':
    src = ((u'有', 'VP'), (u'什么', '~'), (u'手机', 'NP'), (u'？', 'PU'))
    dst = ('VP', '~', 'NP')
    judger = Judger(grammar_calculator)
    print 'score:', judger.get_score(src, dst)
